pacman::p_load(ggiraph, plotly, patchwork, DT, tidyverse) Hands-On Exercise 3
In this Hands-On Exercise, we explore how to add interactive elements and animations to visualisations using appropriate R packages.
Interactive Data Viz
Getting Started
Install and Load Required Packages
The code chunk below will be used to check if these packages have been installed and also will load them onto your working R environment:
Import the Data
exam_data <- read_csv("data/Exam_data.csv")Rows: 322 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (4): ID, CLASS, GENDER, RACE
dbl (3): ENGLISH, MATHS, SCIENCE
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ggigraph Methods
Tooltips
The following code generates an interactive version of a dotplot, and displays the ID value (student ID) when the cursor hovers over a given dot.
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(tooltip=ID),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 6,
height_svg = 6*0.618
)The following code shows how the tooltip content can be customised:
exam_data$tooltip <- c(paste0(
"Name = ", exam_data$ID,
"\n",
"Class = ", exam_data$CLASS
))
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(tooltip=tooltip),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 8,
height_svg = 8*0.618
)Tooltips can be formatted using CSS, like so:
tooltip_css <- "background-color:white; font-style:bold; color: black"
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(tooltip=ID),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 6,
height_svg = 6*0.618,
options = list(opts_tooltip(css = tooltip_css))
)Tooltips can even be customised using a function, for example to show computed statistics:
tooltip <- function(y, ymax, accuracy=0.01) {
mean <- scales::number(y, accuracy = accuracy)
sem <- scales::number(ymax - y, accuracy = accuracy)
paste("Mean maths scores:", mean, "+/-", sem)
}
gg_point <- ggplot(data=exam_data,
aes(x=RACE)) +
stat_summary(aes(y=MATHS,
tooltip = after_stat(tooltip(y,ymax))),
fun.data = 'mean_se',
geom = GeomInteractiveCol,
fill = 'light blue'
) +
stat_summary(aes(y=MATHS),
fun.data = mean_se,
geom = 'errorbar', width = 0.2, size = 0.2
)
girafe(ggobj = gg_point,
width_svg = 8,
height_svg = 8*0.618)Hover effect (using data_id)
Here, when we hover over a data point, all other points with the same CLASS value (i.e. classmates) will be highlighted as well.
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(data_id = CLASS),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot') +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 6,
height_svg = 6*0.618
)By default, the highlighted dots are shown in orange. This can be changed using CSS:
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(data_id = CLASS),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot') +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 6,
height_svg = 6*0.618,
options = list(
opts_hover(css = "fill:#202020;"),
opts_hover_inv(css = "opacity:0.2;")
)
)Combining tooltips and hover effect
Tooltips and hover effect can be combined, so that when we mouse over a data point, all the data points of the same class will be highlighted, and at the same time the name of the class will also be shown:
p <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(tooltip = CLASS,
data_id = CLASS),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
scale_y_continuous(NULL, breaks = NULL)
girafe(
ggobj = p,
width_svg = 6,
height_svg = 6*0.618,
options = list(
opts_hover(css = "fill:#202020;"),
opts_hover_inv(css = "opacity:0.2;")
)
)Coordinated multiple views
By combining ggiraph and patchwork, we can create coordinated graphs such that when a data point in the first graph is selected, the corresponding data point in the second graph will also be highlighted.
p1 <- ggplot(data=exam_data,
aes(x=MATHS)) +
geom_dotplot_interactive(
aes(data_id = ID),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
coord_cartesian(xlim=c(0,100)) +
scale_y_continuous(NULL, breaks = NULL)
p2 <- ggplot(data=exam_data,
aes(x=ENGLISH)) +
geom_dotplot_interactive(
aes(data_id = ID),
stackgroups = TRUE,
binwidth = 1,
method = 'histodot'
) +
coord_cartesian(xlim=c(0,100)) +
scale_y_continuous(NULL, breaks = NULL)
girafe(code = print(p1 + p2),
width_svg = 6,
height_svg = 3,
options = list(
opts_hover(css = "fill:#202020;"),
opts_hover_inv(css = "opacity:0.2;")
)
)Interactive Web Data Viz using plotly
Simple scatter plot using plot_ly() method
plot_ly(data = exam_data,
x = ~MATHS,
y = ~ENGLISH,
color = ~CLASS)No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plotly.com/r/reference/#scatter
No scatter mode specifed:
Setting the mode to markers
Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Same scatter plot using plotly: ggplotly() method
p <- ggplot(data=exam_data,
aes(x=MATHS,
y=ENGLISH)) +
geom_point(size=1) +
coord_cartesian(xlim=c(0,100),
ylim=c(0,100))
ggplotly(p)Coordinated multiple views using ggplotly()
d <- highlight_key(exam_data)
p1 <- ggplot(data=d,
aes(x=MATHS,
y=ENGLISH)) +
geom_point(size=1) +
coord_cartesian(xlim=c(0,100),
ylim=c(0,100))
p2 <- ggplot(data=d,
aes(x=MATHS,
y=SCIENCE)) +
geom_point(size=1) +
coord_cartesian(xlim=c(0,100),
ylim=c(0,100))
subplot(ggplotly(p1),
ggplotly(p2))Interactive Data Tables
DT::datatable(exam_data, class= "compact")Linking data table with plot
d <- highlight_key(exam_data)
p <- ggplot(d,
aes(ENGLISH, MATHS)) +
geom_point(size=1) +
coord_cartesian(xlim=c(0,100),
ylim=c(0,100))
gg <- highlight(ggplotly(p), 'plotly_selected')
crosstalk::bscols(gg,
DT::datatable(d),
widths=5)Setting the `off` event (i.e., 'plotly_deselect') to match the `on` event (i.e., 'plotly_selected'). You can change this default via the `highlight()` function.
Animation
Getting Started
Install and Load Required Packages
pacman::p_load(readxl, gifski, gapminder,
plotly, gganimate, tidyverse)Installing package into 'C:/Users/yang_/AppData/Local/R/win-library/4.2'
(as 'lib' is unspecified)
Warning: unable to access index for repository http://www.stats.ox.ac.uk/pub/RWin/bin/windows/contrib/4.2:
cannot open URL 'http://www.stats.ox.ac.uk/pub/RWin/bin/windows/contrib/4.2/PACKAGES'
package 'gifski' successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\yang_\AppData\Local\Temp\Rtmpy6Q5gL\downloaded_packages
gifski installed
Warning: package 'gifski' was built under R version 4.2.3
Installing package into 'C:/Users/yang_/AppData/Local/R/win-library/4.2'
(as 'lib' is unspecified)
Warning: unable to access index for repository http://www.stats.ox.ac.uk/pub/RWin/bin/windows/contrib/4.2:
cannot open URL 'http://www.stats.ox.ac.uk/pub/RWin/bin/windows/contrib/4.2/PACKAGES'
package 'gapminder' successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\yang_\AppData\Local\Temp\Rtmpy6Q5gL\downloaded_packages
gapminder installed
Warning: package 'gapminder' was built under R version 4.2.3
Import the Data
cols <- c('Country', 'Continent')
globalPop <- read_xls('data/GlobalPopulation.xls',
sheet='Data') %>%
mutate(across(all_of(cols), ~ factor(.x))) %>%
mutate(Year = as.integer(Year))Adding animations using gganimate
Population bubble plot
Start with a static bubble plot:
ggplot(data=globalPop,
aes(x=Old,
y=Young,
size=Population,
colour=Country)) +
geom_point(alpha = 0.7,
show.legend = FALSE) +
scale_color_manual(values = country_colors) +
scale_size(range = c(2,12)) +
labs(title = 'Year: {frame_time}',
x = '% Aged',
y = '% Young')
Add animation by creating transitions across Years:
ggplot(data=globalPop,
aes(x=Old,
y=Young,
size=Population,
colour=Country)) +
geom_point(alpha = 0.7,
show.legend = FALSE) +
scale_color_manual(values = country_colors) +
scale_size(range = c(2,12)) +
labs(title = 'Year: {frame_time}',
x = '% Aged',
y = '% Young') +
transition_time(Year) +
ease_aes('linear')
Adding animations using plotly
Using ggplotly() method
gg <- ggplot(data=globalPop,
aes(x=Old,
y=Young,
size=Population,
colour=Country)) +
geom_point(aes(size = Population,
frame = Year),
alpha = 0.7,
show.legend = FALSE) +
scale_colour_manual(values = country_colors) +
scale_size(range = c(2,12)) +
labs(x = '% Aged',
y = '% Young')Warning: Ignoring unknown aesthetics: frame
ggplotly(gg)Warning in p$x$data[firstFrame] <- p$x$frames[[1]]$data: number of items to
replace is not a multiple of replacement length
Using plot_ly() method
bp <- globalPop %>%
plot_ly(x = ~Old,
y = ~Young,
size = ~Population,
color = ~Continent,
frame = ~Year,
text = ~Country,
hoverinfo = 'text',
type = 'scatter',
mode = 'markers')
bp